/*
 * MIT License
 * 
 * Copyright (c) 2017 wen.gu <454727014@qq.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
 
/***************************************************************************
 * Name: tiny_string.c
 *
 * Purpose: string operation define 
 *
 * Developer:
 *   wen.gu , 2016-01-19
 *
 * TODO: 
 *
 ***************************************************************************/

#include "tiny_string.h"



/***************************************************************************
 *
 * API define
 *
 ***************************************************************************/
GU32 tfStrlcpy(char *dst, const char *src, GU32 size)
{
    GU32 len = 0;
    while (++len < size && *src)
    {
        *dst++ = *src++;
    }

    if (len <= size)
    {
        *dst = 0;
    }

    return len + strlen(src) - 1;
}

////////////////////////////////////////////////////////////////////////////
// Utility functions
////////////////////////////////////////////////////////////////////////////

static inline size_t _str_len_16(const GS16 * str)
{
    size_t len;
    for (len = 0; *str; str++)
        len++;
    return len;
}

static inline size_t _str_len(const GS08 * str)
{
    size_t len;
    for (len = 0; *str; str++)
        len++;
    return len;
}

static inline size_t _str_nlen_16(const GS16 * str, size_t maxcount)
{
    size_t len;
    for (len = 0; len < maxcount && *str; str++)
        len++;
    return len;
}

static inline size_t _str_nlen(const GS08 * str, size_t maxcount)
{
    size_t len;
    for (len = 0; len < maxcount && *str; str++)
        len++;
    return len;
}

static inline size_t _str_cpy_16(GS16 * dst, const GS16 * src)
{
    size_t count;
    for (count = 0; (*dst++ = *src++); count++)
        ;
    return count;
}

static inline size_t _str_cpy(GS08 * dst, const GS08 * src)
{
    size_t count;
    for (count = 0; (*dst++ = *src++); count++)
        ;
    return count;
}

static inline size_t _str_cpy_16_8(GS16 * dst, const GS08 * src)
{
    size_t count;
    for (count = 0; (*dst++ = *src++); count++)
        ;
    return count;
}

static inline size_t _str_cpy_8_16(GS08 * dst, const GS16 * src)
{
    size_t count;
    for (count = 0; (*dst++ = (GS08)*src++); count++)
        ;
    return count;
}

static inline size_t _str_ncpy_16(GS16 * dst, const GS16 * src, size_t maxcount)
{
    size_t count = 0;
    do
    {
        if (++count > maxcount)
        {
            *dst = 0;
            return count;
        }
    } while ((*dst++ = *src++));
    return count;
}

static inline size_t _str_ncpy(GS08 * dst, const GS08 * src, size_t maxcount)
{
    size_t count = 0;
    do
    {
        if (++count > maxcount)
        {
            *dst = 0;
            return count;
        }
    } while ((*dst++ = *src++));
    return count;
}

static inline void _str_memcpy_16(GS16 * dst, const GS16 * src, size_t count)
{
    while (count-- > 0)
        (*dst++ = *src++);
}

static inline void _str_memcpy(GS08 * dst, const GS08 * src, size_t count)
{
    while (count-- > 0)
        (*dst++ = *src++);
}

static inline void _str_memset_16(GS16 * dst, GS16 value, size_t count)
{
    while (count-- > 0)
        *dst++ = value;
}

static inline void _str_memset(GS08 * dst, GS08 value, size_t count)
{
    while (count-- > 0)
        *dst++ = value;
}

/**
*@brief  get char 16 string length
*
* @param str [in]  char 16 string
*
*@retuen the length of str.
*@see
*/
GU32 tfStrLen16(const GS16 *str)
{
    return _str_len_16(str);
}

/**
*@brief  get char 16 string length with max count limit
*
* @param str      [in]  char 16 string
*        maxcount [in]  max count limit
*
*@retuen the length of str.
*@see
*/
GU32 tfStrnLen16(const GS16 *str, GU32 maxcount)
{
    return _str_nlen_16(str, maxcount);
}

/**
*@brief  copy char 16 string
*
* @param dst [io] destination char 16 string
*        src [in] source char 16 string
*
*@retuen source char 16 string length.
*@see
*/
GU32 tfStrCpy16(GS16 *dst, const GS16 *src)
{
    return _str_cpy_16(dst, src);
}

/**
*@brief  copy a char 8 string to char 16 string
*
* @param dst [io] destination char 16 string
*        src [in] source char 8 string
*
*@retuen source char 8 string length.
*@see
*/
GU32 tfStrCpy16_8(GS16 *dst, const GS08 *src)
{
    return _str_cpy_16_8(dst, src);
}

/**
*@brief  copy char 16 string with max count limit
*
* @param dst [io] destination char 16 string
*        src [in] source char 16 string
*        maxcount [in] max count limit
*
*@retuen source char 16 string length or maxcount.
*@see
*/
GU32 tfStrnCpy16(GS16 *dst, const GS16 *src, GU32 maxcount)
{
    return _str_ncpy_16(dst, src, maxcount);
}

/**
*@brief  copy 'count' number of char 16
*
* @param dst [io] destination char 16 string
*        src [in] source char 16 string
*        count [in] the number of char 16
*
*@retuen None.
*@see
*/
void tfStrMemCpy16(GS16 *dst, const GS16 *src, GU32 count)
{
    _str_memcpy_16(dst, src, count);
}

/**
*@brief  memory set with 'value'
*
* @param dst   [io] destination char 16 string
*        value [in] the value of a char 16
*        count [in] the number of char 16
*
*@retuen None.
*@see
*/
void tfStrMemSet16(GS16 *dst, GS16 value, GU32 count)
{
    _str_memset_16(dst, value, count);
}

/**
*@brief  compare two char 16 string
*
* @param str1 [in] a char 16 string
*        str2 [in] a char 16 string
*
*@retuen str1 < str2 : return negative number(-1)
*        str1 == str2: return 0.
*        str1 > str2 : return positive number(1)
*@see
*/
GS32  tfStrCmp16(const GS16 *str1, const GS16 *str2)
{
    while (*str1 == *str2)
    {
        if (!*str1)
            return 0;
        ++str1;
        ++str2;
    }
    if (*str1 > *str2)
        return 1;
    else
        return -1;
}

/**
*@brief  compare a char 16 string and a char 8 string
*
* @param str1 [in] a char 16 string
*        str2 [in] a char 8 string
*
*@retuen str1 < str2 : return negative number(-1)
*        str1 == str2: return 0.
*        str1 > str2 : return positive number(1)
*@see
*/
GS32  tfStrCmp16_8(const GS16 *str1, const GS08 *str2)
{
    while (*str1 == (GS16)*str2)
    {
        if (!*str1)
            return 0;
        ++str1;
        ++str2;
    }
    if (*str1 > (GS16)*str2)
        return 1;
    else
        return -1;
}

/**
*@brief  convert a char 16 string to uppercase
*
* @param str [io] a char 16 string
*        len [in] char 16 string length
*
*@retuen None.
*@see
*/
void tfStrUppercase16(GS16 *str, GS32 len)
{
    GS32 i = 0;
    for (; i < len; i++) {
        GS16 ch = str[i];
        if (ch >= 'a' && ch <= 'z') {
            str[i] = ch - 0x20;
        }
        else if (ch >= 0xE0 && ch <= 0xFF) {
            str[i] = ch - 0x20;
        }
        else if (ch >= 0x430 && ch <= 0x44F) {
            str[i] = ch - 0x20;
        }
    }
}

/**
*@brief  convert a char 16 string to lowercase
*
* @param str [io] a char 16 string
*        len [in] char 16 string length
*
*@retuen None.
*@see
*/
void tfStrLowercase16(GS16 *str, GS32 len)
{
    GS32 i = 0;
    for (; i < len; i++) {
        GS16 ch = str[i];
        if (ch >= 'A' && ch <= 'Z') {
            str[i] = ch + 0x20;
        }
        else if (ch >= 0xC0 && ch <= 0xDF) {
            str[i] = ch + 0x20;
        }
        else if (ch >= 0x410 && ch <= 0x42F) {
            str[i] = ch + 0x20;
        }
    }
}

//////////////////////////////////////////////////////////////////////////
/**
*@brief get char 8 string length
*
* @param str [in] char 8 string
* @return
*
*@retuen the length of str.
*@see
*/
GU32 tfStrLen(const GS08 *str)
{
    return _str_len(str);
}

/**
*@brief  get char 8 string length with max count limit
*
* @param str      [in]  char 8 string
*        maxcount [in]  max count limit
*
*@retuen the length of str.
*@see
*/
GU32 tfStrnLen(const GS08 *str, GU32 maxcount)
{
    return _str_nlen(str, maxcount);
}

/**
*@brief  copy char 8 string
*
* @param dst [io] destination char 8 string
*        src [in] source char 8 string
*
*@retuen source char 8 string length.
*@see
*/
GU32 tfStrCpy(GS08 *dst, const GS08 *src)
{
    return _str_cpy(dst, src);
}

/**
*@brief  copy char 8 string with max count limit
*
* @param dst [io] destination char 8 string
*        src [in] source char 8 string
*        maxcount [in] max count limit
*
*@retuen source char 8 string length or maxcount.
*@see
*/
GU32 tfStrnCpy(GS08 *dst, const GS08 *src, GU32 maxcount)
{
    return _str_ncpy(dst, src, maxcount);
}

/**
*@brief  copy 'count' number of char 8
*
* @param dst   [io] destination char 8 string
*        src   [in] source char 8 string
*        count [in] the number 8 char 8
*
*@retuen None.
*@see
*/
void tfStrMemCpy(GS08 *dst, const GS08 *src, GU32 count)
{
    _str_memcpy(dst, src, count);
}

/**
*@brief  memory set with 'value'
*
* @param dst   [io] destination char 8 string
*        value [in] the value of a char 8
*        count [in] the number of char 8
*
*@retuen None.
*@see
*/
void tfStrMemSet(GS08 *dst, GS08 value, GU32 count)
{
    _str_memset(dst, value, count);
}

/**
*@brief  compare two char 8 string
*
* @param str1 [in] a char 8 string
*        str2 [in] a char 8 string
*
*@retuen str1 < str2 : return negative number(-1)
*        str1 == str2: return 0.
*        str1 > str2 : return positive number(1)
*@see
*/
GS32  tfStrCmp(const GS08 *str1, const GS08 *str2)
{
    while (*str1 == *str2)
    {
        if (!*str1)
            return 0;
        ++str1;
        ++str2;
    }
    if (*str1 > *str2)
        return 1;
    else
        return -1;
}

/**
*@brief  compare a char 8 string and a char 16 string
*
* @param str1 [in] a char 8 string
*        str2 [in] a char 16 string
*
*@retuen str1 < str2 : return negative number(-1)
*        str1 == str2: return 0.
*        str1 > str2 : return positive number(1)
*@see
*/
GS32  tfStrCmp8_16(const GS08 *str1, const GS16 *str2)
{
    while ((GS16)*str1 == *str2)
    {
        if (!*str1)
            return 0;
        ++str1;
        ++str2;
    }
    if ((GS16)*str1 > *str2)
        return 1;
    else
        return -1;
}